home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
boot
/
czesc_2
/
snap
/
snapchars.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-04
|
20KB
|
1,025 lines
#include "Snap.h"
IMPORT struct SnapRsrc *SnapRsrc;
#define COPY 0xC0L
#define INVCOPY 0x30L
#define CopyChar(_x, _y, _m) \
BltBitMap(&MyBM, (LONG)_x, (LONG)_y, \
&TempBM, 0L, 0L, (LONG)FontWidth, (LONG)FontHeight, \
_m, -1L, NULL); \
WaitBlit()
WORD Unit;
UWORD Pattern[5] =
{
0,
0x0c3f, /* Frame ....oo....oooooo */
0x3333, /* Char ..oo..oo..oo..oo */
0x1f1f, /* Word ...ooooo...ooooo */
0xffff /* Line oooooooooooooooo */
};
LONG xl; /* leftmost x position */
LONG xr; /* rightmost x position */
LONG yt; /* topmost y position */
LONG yb; /* bottommost y position */
LONG minx; /* left limit */
LONG maxx; /* right limit */
LONG maxy; /* bottom limit */
LONG tl, tr; /* used by findword - left and right edge of word */
WORD fw, fh; /* Font width and height used when drawing the frame */
WORD GZZ;
WORD SBM;
LONG mx, my; /* Mouse position in character steps */
#define closetop 0
#define closebottom 1
WORD closey;
#define closeleft 0
#define closeright 1
WORD closex;
struct Window *window; /* The window we're snapping from */
/* Data for font being snapped */
UWORD FontHeight;
UWORD FontWidth;
UWORD Underscore;
UBYTE FontType;
UBYTE LoChar;
UBYTE HiChar;
UWORD Modulo;
UWORD *CharLoc;
UWORD *CharKern;
UBYTE *SrcData;
IMPORT UBYTE *CharData;
UBYTE IFlags;
IMPORT struct RastPort TempRp, MyRP;
IMPORT struct BitMap TempBM, MyBM;
IMPORT UWORD *TempRaster; /* Used for character recognition */
IMPORT struct Screen *theScreen;
IMPORT struct RastPort rp;
struct Layer *LockedLayer;
IMPORT struct timerequest MyTR;
IMPORT LONGBITS cancelsignal, donesignal, movesignal;
IMPORT LONGBITS clicksignal, ticksignal, timersignal;
IMPORT WORD action;
WORD starting;
/* Init vars with font data.
*/
WORD SetSnapFont(font)
struct TextFont *font;
{
if (!font)
{
return 0;
}
FontHeight = font->tf_YSize;
if (FontHeight > CHEIGHT)
{
return 0;
}
Underscore = font->tf_Baseline + 1;
FontType = font->tf_Flags;
if (FontType & FPF_PROPORTIONAL)
{
return 0;
}
FontWidth = font->tf_XSize;
LoChar = font->tf_LoChar;
HiChar = font->tf_HiChar;
Modulo = font->tf_Modulo;
CharLoc = (UWORD *) font->tf_CharLoc;
CharKern = (UWORD *) font->tf_CharKern;
Modulo = font->tf_Modulo;
SrcData = (UBYTE *) font->tf_CharData;
BltClear((char *)CharData, 256L * (CHEIGHT * 2), 0L);
WaitBlit();
CopyFont();
return 1;
}
/* Check if the character at x, y is a space
*/
WORD SnapIsSpace(x, y)
LONG x, y;
{
REGISTER WORD i = FontHeight - 1;
REGISTER UWORD *data = &TempRaster[i];
/* Copy character at x, y */
BltClear((char *)TempRaster, CHEIGHT * 2L, 0L);
ClipBlit(&rp, x, y,
&TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
WaitBlit();
if (*data)
{ /* Try inverted copy */
ClipBlit(&rp, x, y,
&TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, INVCOPY);
WaitBlit();
}
while (i--)
{
if (*data--)
{
return 0;
}
}
return 1;
}
#define ShortFrame 4L /* Square frame - columnar select */
#define LongFrame 8L /* Strange frame - char or word select */
IMPORT LONG OFType; /* Old frame type: ShortFrame/LongFrame */
IMPORT UWORD Ptrn;
IMPORT Point OldFrame[];
IMPORT Point NewFrame[];
/* update_frame calculates the new frame,
** erases the old frame and draws the new one.
** It's all pretty obvious if you take it slowly.
*/
VOID update_frame()
{
LONG ft;
REGISTER LONG l, b, r, t, ml, mr;
l = xl - 1;
r = xr + fw;
t = yt - 1;
b = yb + fh;
ml = minx - 1;
mr = maxx + fw;
if (l < 0)
l = 0;
if (r > window->Width - 1)
r = window->Width - 1;
if (t < 0)
t = 0;
if (b > window->Height - 1)
b = window->Height - 1;
if (ml < 0)
ml = 0;
if (mr > window->Width - 1)
mr = window->Width - 1;
switch (Unit)
{
case UNIT_FRAME:
{
/*********\
* *
* *
\*********/
NewFrame[0].x = l;
NewFrame[0].y = t;
NewFrame[1].x = r;
NewFrame[1].y = t;
NewFrame[2].x = r;
NewFrame[2].y = b;
NewFrame[3].x = l;
NewFrame[3].y = b;
NewFrame[4].x = l;
NewFrame[4].y = t;
ft = ShortFrame;
break;
}
case UNIT_CHAR:
case UNIT_WORD:
{
if (yt == yb)
{ /* On the same line - same as UNIT_FRAME */
NewFrame[0].x = l;
NewFrame[0].y = t;
NewFrame[1].x = r;
NewFrame[1].y = t;
NewFrame[2].x = r;
NewFrame[2].y = b;
NewFrame[3].x = l;
NewFrame[3].y = b;
NewFrame[4].x = l;
NewFrame[4].y = t;
ft = ShortFrame;
}
else
{
/*****\
****** *
* *
* *****
*******/
NewFrame[0].x = l;
NewFrame[0].y = t;
NewFrame[1].x = mr;
NewFrame[1].y = t;
NewFrame[2].x = mr;
NewFrame[2].y = yb;
NewFrame[3].x = r;
NewFrame[3].y = yb;
NewFrame[4].x = r;
NewFrame[4].y = b;
NewFrame[5].x = ml;
NewFrame[5].y = b;
NewFrame[6].x = ml;
NewFrame[6].y = yt + fh;
NewFrame[7].x = l;
NewFrame[7].y = yt + fh;
NewFrame[8].x = l;
NewFrame[8].y = t;
ft = LongFrame;
}
break;
}
case UNIT_LINE:
{
NewFrame[0].x = ml;
NewFrame[0].y = t;
NewFrame[1].x = mr;
NewFrame[1].y = t;
NewFrame[2].x = mr;
NewFrame[2].y = b;
NewFrame[3].x = ml;
NewFrame[3].y = b;
NewFrame[4].x = ml;
NewFrame[4].y = t;
ft = ShortFrame;
break;
}
default:
{
break;
}
}
draw_frame(ft);
}
VOID FindWord()
{
/* Must remove frame to be able to search for spaces */
WaitTOF();
erase_frame();
tl = mx;
/* Find a space to the left... */
while (!SnapIsSpace(tl, my))
{
tl -= fw;
if (tl < minx)
{
break;
}
}
tl += fw;
tr = mx;
/* ...and to the right */
while (!SnapIsSpace(tr, my))
{
tr += fw;
if (tr + fw > maxx)
{
break;
}
}
tr -= fw;
if (tr < tl)
{
tl = xl;
tr = xr;
}
}
/* ChangeUnit cycles the unit of selection. The differents units
are: character, word and line.
*/
VOID ChangeUnit()
{
switch (Unit)
{
case UNIT_FRAME:
{
Unit = UNIT_CHAR;
break;
}
case UNIT_CHAR:
{
Unit = UNIT_WORD;
FindWord();
xl = tl;
xr = tr;
break;
}
case UNIT_WORD:
{
Unit = UNIT_LINE;
xl = minx;
xr = maxx;
break;
}
case UNIT_LINE:
{
Unit = UNIT_FRAME;
xl = xr = mx;
break;
}
}
if (SnapRsrc->CrawlPtrn == 0)
{
Ptrn = Pattern[Unit];
}
}
/* ExtendSelection extends the current selection according to
the mouse position and the selected unit.
Note that ExtendSelection doesn't optimize moves that don't
make any difference. FIXME
*/
VOID ExtendSelection()
{
/* Fix which row we're talking about */
if (closey == closetop)
{ /* Find closest row */
yt = my; /* change top row */
}
else
{
yb = my; /* change bottom row */
}
/* Take care of left and right character pos */
switch (Unit)
{
case UNIT_FRAME:
{
if (closex == closeleft)
{
xl = mx;
}
else
{
xr = mx;
}
break;
}
case UNIT_CHAR:
{
if (yt == yb)
{ /* One line */
if (closex == closeleft)
{
xl = mx;
}
else
{
xr = mx;
}
}
else
{ /* Multiple lines */
if (yt == my)
{
xl = mx; /* At top - set left */
}
else
{
xr = mx; /* At bottom - set right */
}
}
break;
}
case UNIT_WORD:
{
FindWord(); /* Find the word */
if (yt == yb)
{ /* One line */
if (closex == closeleft)
{ /* Find closest char pos */
xl = tl;
}
else
{
xr = tr;
}
}
else
{ /* Multiple lines */
if (yt == my)
{ /* Where am I */
xl = tl; /* At top - set left */
}
else
{
xr = tr; /* At bottom - set right */
}
}
break;
}
case UNIT_LINE:
{ /* Always full width */
break;
}
}
if (yt - fh == yb)
{
yb += fh;
}
if (yt == yb && xl - fw == xr)
{
xr += fw;
}
if (xr > maxx)
{ /* Check for window bounds */
xr = maxx;
}
if (xl < minx)
{ /* Check for window bounds */
xl = minx;
}
if (yb > maxy)
{ /* Check for window bounds */
yb = maxy;
}
if (xl > maxx)
{
xl = maxx;
}
if (xr < minx)
{
xr = minx;
}
}
/* The actual character snapper. It actually works. :-) */
WORD SnapChars()
{
LONG width;
LONG height;
UBYTE *SnapSpace;
ULONG SnapSize;
ULONG counter;
REGISTER LONG x, y;
/* Check coordinates */
if (yt - fh == yb)
{ /* No rows, shouldn't happen */
return 0;
}
if (yt == yb && xl - fw == xr)
{ /* Nothing at all */
return 0;
}
/* Calculate stuff */
width = maxx - (minx + 1) + fw + fw; /* Add one for a LF */
height = yb - yt + fh;
SnapSize = ((width / fw) + 1) * (height / fh);
counter = 0;
/* Initialize things */
InitRastPort(&MyRP);
InitBitMap(&MyBM, 1L, width, height);
MyRP.BitMap = &MyBM;
SnapSpace = AllocMem(SnapSize, MEMF_PUBLIC | MEMF_CLEAR);
/* Please insert more memory */
if (!SnapSpace)
{
return 0;
}
MyBM.Planes[0] = AllocRaster(width, height);
if (!MyBM.Planes[0])
{
FreeMem(SnapSpace, SnapSize);
return 0;
}
IFlags = 0;
/* Make a local copy of the snapped chars */
ClipBlit(&rp, minx, yt, &MyRP, 0L, 0L, width, height, COPY);
/* Ok, now we've got a copy of the character data */
/* Now it's ok to mess with the layers again */
UnlockLayer(LockedLayer);
/* Clear our work area */
BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
/* Calculate bounds */
xl -= minx;
xr -= minx;
maxx -= minx;
minx = 0;
yb -= yt;
yt = 0;
/* Single line - needs to be handled separately */
if (yt == yb)
{ /* Ok, we've got one */
/* Read from left to right */
for (x = xl; x <= xr; x += fw, counter++)
{
CopyChar(x, yt, COPY);
if (!(SnapSpace[counter] = interpret(TempRaster)))
{
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_LINE)
{
while (counter && SnapSpace[counter - 1] == ' ')
{
counter--;
}
}
}
else
{ /* Multiple lines */
if (Unit == UNIT_FRAME)
{
minx = xl;
maxx = xr;
}
/* Read first line */
for (x = xl; x <= maxx; x += fw, counter++)
{
CopyChar(x, yt, COPY);
if (!(SnapSpace[counter] = interpret(TempRaster)))
{
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_FRAME)
{
SnapSpace[counter++] = 10;
}
else
{
SHORT endspace = (SnapSpace[counter - 1] == ' ');
/* Remove trailing blanks */
while (counter && SnapSpace[counter - 1] == ' ')
{
counter--;
}
if (endspace || !(SnapRsrc->flags & JOINLONG))
{
SnapSpace[counter++] = 10;
}
}
/* If more than two rows - read full middle rows */
if (yt + fh != yb)
{
for (y = yt + fh; y < yb; y += fh)
{
for (x = minx; x <= maxx; x += fw, counter++)
{
CopyChar(x, y, COPY);
if (!(SnapSpace[counter] = interpret(TempRaster)))
{
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
if (Unit == UNIT_FRAME)
{
SnapSpace[counter++] = 10;
}
else
{
SHORT endspace = (SnapSpace[counter - 1] == ' ');
/* Remove trailing blanks */
while (counter && SnapSpace[counter - 1] == ' ')
{
counter--;
}
if (endspace || !(SnapRsrc->flags & JOINLONG))
{
SnapSpace[counter++] = 10;
}
}
}
}
/* Read last line */
for (x = minx; x <= xr; x += fw, counter++)
{
CopyChar(x, yb, COPY);
if (!(SnapSpace[counter] = interpret(TempRaster)))
{
SnapSpace[counter] = SnapRsrc->BadChar; /* Unrecognized */
}
}
/* Remove trailing blanks */
while (counter && SnapSpace[counter - 1] == ' ')
{
counter--;
}
}
FreeRaster(MyBM.Planes[0], width, height);
SaveClip(SnapSpace, counter);
FreeMem(SnapSpace, SnapSize);
return 1;
}
/* HandleChars is the part of the Snap state machine that handles
snapping of characters. The selection is done in different
units: char, word, line.
*/
WORD HandleChars()
{
LONG xoff, yoff;
LONG ox, oy;
LONG gzzx, gzzy, normalx, normaly;
/* Find out which screen we're working on */
theScreen = WhichScreen();
/* Oops, no screen? */
if (!theScreen)
{
action = noaction;
return 0;
}
/* Ok, what window? */
window = WhichWindow(theScreen);
/* Oh dear, no window. */
if (!window)
{
action = noaction;
return 0;
}
/* Try to get these as early as possible */
gzzx = window->GZZMouseX;
gzzy = window->GZZMouseY;
normalx = window->MouseX;
normaly = window->MouseY;
/* No messing with the layers while I think */
LockedLayer = window->WLayer;
LockLayer(0L, LockedLayer);
/* Don't want to wreck somebody's rastport */
CopyMem((char *)window->RPort, (char *)&rp, (LONG) sizeof (struct RastPort));
/* Or his picture */
SetDrMd(&rp, COMPLEMENT);
rp.Mask = SnapRsrc->FrameMask;
if (window->Flags & GIMMEZEROZERO)
{
GZZ = 1;
}
else
{
GZZ = 0;
}
if (window->Flags & SUPER_BITMAP)
{
SBM = 1;
}
else
{
SBM = 0;
}
/* Find a position */
xl = (GZZ ? gzzx : normalx) + window->RPort->Layer->Scroll_X;
yt = (GZZ ? gzzy : normaly) + window->RPort->Layer->Scroll_Y;
if (xl < 0)
{
xl = 0;
}
if (yt < 0)
{
yt = 0;
}
/* Check your position */
if (xl > (GZZ ? window->GZZWidth : window->Width) ||
yt > (GZZ ? window->GZZHeight : window->Height))
{
UnlockLayer(LockedLayer);
action = noaction;
return 0;
}
IFlags = 0;
/* Find out the offset for the clicked character, if any.
** This is the part that makes it special. Simple, isn't it. Hah!
*/
{
REGISTER struct CacheWindow *cw = GetCachedWindow(theScreen, window);
struct TextFont *font[3];
WORD fonts = 0;
/* Collect fonts to try */
if (SnapRsrc->AlternateFont)
{ /* The alternate font */
font[fonts++] = SnapRsrc->AlternateFont;
}
font[fonts++] = rp.Font; /* Second best, the RP's font */
if (cw)
{ /* Best bet, the cached font */
font[fonts++] = cw->font;
}
while (fonts--)
{
SHORT xadj;
SHORT yadj;
SHORT seekw;
SHORT seekh;
/* Find out what we're trying to read */
if (!SetSnapFont(font[fonts]))
{
continue; /* Nope, try next font */
}
BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
if (cw)
{
xoff = -((xl - cw->xoff) % cw->fw);
yoff = -((yt - cw->yoff) % cw->fh);
ClipBlit(&rp, xl + xoff, yt + yoff,
&TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
WaitBlit();
if (interpret(TempRaster))
{
goto found;
}
}
/* No cache or cache didn't match */
xadj = (FontWidth < 8 ? FontWidth : 8);
yadj = (FontHeight < 12 ? FontHeight : 12);
seekw = (xadj << 1) - FontWidth;
seekh = (yadj << 1) - FontHeight;
xl -= xadj;
yt -= yadj;
xoff = 0;
while (xoff < seekw)
{
ClipBlit(&rp, xl + xoff, yt,
&TempRp, 0L, 0L, (LONG) FontWidth, CHEIGHT, COPY);
WaitBlit();
yoff = 0;
while (yoff < seekh)
{
if (interpret(&TempRaster[yoff]))
{
goto found;
}
++yoff;
}
++xoff;
}
/* No character found. Try next font. */
xl += xadj; /* Adjust to original values */
yt += yadj;
}
UnlockLayer(LockedLayer);
action = noaction;
return 0;
found:
/* Ok, now we know where to look for chars.
** xoff and yoff is character position within our 16xCHEIGHT bitmap.
*/
xl = xl + xoff; /* Adjust x */
yt = yt + yoff; /* Adjust y */
fw = FontWidth;
fh = FontHeight;
{
SHORT temp = fh;
while (temp <= fh + SnapRsrc->Leading)
{ /* Check for extra pixel row */
BltClear((char *)TempRaster, CHEIGHT * 2, 0L);
ClipBlit(&rp, xl, yt + temp,
&TempRp, 0L, 0L, (LONG) FontWidth, (LONG) FontHeight, COPY);
WaitBlit();
if (interpret(TempRaster))
{
fh = temp;
break;
}
++temp;
}
}
/* Find out offsets within the window */
xoff = xl % fw;
yoff = yt % fh;
if (cw)
{
cw->xoff = xoff;
cw->yoff = yoff;
cw->fw = fw;
cw->fh = fh;
cw->font = font[fonts];
}
else
{
CacheWindow(window, xoff, yoff, fw, fh, font[fonts]);
}
}
/* Set bounds */
minx = xoff;
maxx = minx +
(((GZZ ?
window->GZZWidth :
window->Width - window->BorderRight
/* Hack for borderless conman windows */
+ (window->Flags & BORDERLESS && window->Flags & WINDOWSIZING ? 14 : 0))
- minx - fw) / fw) * fw;
maxy = yoff +
(((GZZ ? window->GZZHeight : window->Height) - yoff - fh) / fh) * fh;
/* Check bounds */
if (xl > maxx)
{
UnlockLayer(LockedLayer);
action = noaction;
return 0;
}
/* Set box dimensions */
xr = xl;
yb = yt;
ox = xr;
oy = yt;
/* Select unit while starting */
starting = 1;
/* Starting unit is character or frame */
Unit = SnapRsrc->StartUnit;
Ptrn = (SnapRsrc->CrawlPtrn ? SnapRsrc->CrawlPtrn : Pattern[Unit]);
OFType = 0L;
update_frame();
/* Get the state machine running */
FOREVER
{
/* Wait for something to happen */
REGISTER LONGBITS sig;
MyTR.tr_time.tv_secs = 0;
MyTR.tr_time.tv_micro = 500000;
MyTR.tr_node.io_Command = TR_ADDREQUEST;
SendIO((struct IORequest *)&MyTR);
sig = Wait(movesignal | cancelsignal | donesignal |
clicksignal | ticksignal | timersignal);
if ((sig & timersignal) && CheckIO((struct IORequest *)&MyTR))
{
WaitIO((struct IORequest *)&MyTR);
erase_frame();
UnlockLayer(LockedLayer); /* Unlock things */
sig = Wait(ticksignal); /* Wait for input handler to become avtive */
LockLayer(0L, LockedLayer); /* Re-lock */
/* I guess I should check to see that the window is still
there. Aw, what the heck. Apologies to anyone who gets
bitten by this. */
DisplayBeep(NULL);
update_frame();
}
else
{
AbortIO((struct IORequest *)&MyTR);
WaitIO((struct IORequest *)&MyTR);
SetSignal(0, timersignal);
}
if ((sig & ticksignal) && (SnapRsrc->CrawlPtrn != 0xffff))
{
crawl_frame(0L);
}
mx = (LONG) (GZZ ? window->GZZMouseX : window->MouseX)
+ window->RPort->Layer->Scroll_X;
if (mx < 0)
{
mx = 0;
}
/* Calculate which edge is closest */
if ((mx - xl) < (xr - mx))
{
closex = closeleft;
}
else
{
closex = closeright;
}
/* Only interested in real char pos */
mx = mx - ((mx - xoff) % fw);
my = (LONG) (GZZ ? window->GZZMouseY : window->MouseY)
+ window->RPort->Layer->Scroll_Y;
if (my < 0)
{
my = 0;
}
/* Calculate which row is closest */
if ((my - yt) < (yb - my))
{
closey = closetop;
}
else
{
closey = closebottom;
}
my = my - ((my - yoff) % fh);
/* Hey, it moves! It's alive!! */
if ((sig & movesignal) && (action == snaptext))
{
if (mx != ox || my != oy)
{ /* Something's happened */
ExtendSelection();
update_frame();
starting = 0;
ox = mx;
oy = my;
sig &= ~clicksignal;
}
}
/* Ok, forget it... */
if (sig & cancelsignal)
{
erase_frame();
UnlockLayer(LockedLayer);
return 0;
}
/* Click */
if ((sig & clicksignal) && (action == snaptext))
{
/* Selecting unit */
if (starting)
{
if (mx == ox && my == oy)
{
ChangeUnit();
if (Unit == UNIT_CHAR)
{
ChangeUnit();
}
update_frame();
}
else if (Unit == UNIT_FRAME)
{
ChangeUnit();
update_frame();
}
}
if (mx != ox || my != oy)
{ /* Click in a new place */
ExtendSelection();
update_frame();
starting = 0;
ox = mx;
oy = my;
}
}
/* Finished */
if (sig & donesignal)
{
erase_frame();
return SnapChars();
}
}
}